iT邦幫忙

2026 iThome 鐵人賽

DAY 20
0
Software Development

程式設計沒有告訴你的事:30 天破解每一個 Why系列 第 20

JSON 明明只是一串文字,Framework 為什麼可以把它變成 C# 物件?

  • 分享至 

  • xImage
  •  

昨天理解 Request Body 之後,我開始知道,POST 傳來的資料可能會放在 Body 裡。

例如:

{"name":"Andy","age":20}

但這時又出現一個很直覺的問題。

這明明只是一串文字。

為什麼平常在 ASP.NET Core 裡,卻可以直接拿到:

Name = Andy

Age = 20

甚至直接得到一個 C# 物件?

所以今天想理解的問題就是:

JSON 明明只是一串文字,Framework 為什麼可以把它變成 C# 物件?

💭 我原本以為……

以前寫 Web API 時,我很容易把:

Client 傳 JSON

Controller 收到 Model

當成一件很自然的事情。

例如 Client 傳:

{"name":"Andy","age":20}

Server 端可能就可以直接使用:

user.Name

user.Age

以前會覺得,好像 JSON 本身就知道 C# Class 長什麼樣。

但其實這當然不可能。

Client 傳來的只是文字資料。

而 C# 裡的物件則是記憶體中的程式資料結構。

中間一定還需要一個轉換步驟。

JSON 到底是什麼?

JSON 是一種文字格式。

例如:

{"name":"Andy","age":20}

它本身只是由一些字元組成。

其中:

"name"

是一個欄位名稱。

"Andy"

是一個字串值。

"age"

也是欄位名稱。

20

是一個數值。

所以 JSON 的目的,是用一種固定格式描述資料。

可以把它理解成:

文字

但有結構

它不是單純的一句話,而是一種規則明確的資料表示方式。

為什麼 Framework 看得懂?

因為 JSON 有自己的格式規則。

例如:

{}

代表 Object。

[]

代表 Array。

:

用來分隔欄位名稱和值。

,

用來分隔不同欄位。

所以:

{"name":"Andy","age":20}

Framework 並不是「看字猜意思」。

而是按照 JSON 規則解析。

可以想成:

Raw JSON

找到 Object

找到 name

找到 "Andy"

找到 age

找到 20

最後整理成:

name → Andy
age → 20

這個過程就是 Parsing。

從 JSON 變成 C# 物件又多了一步

光把 JSON 解析成:

name → Andy
age → 20

還不代表它已經是 C# 物件。

假設程式裡有一個:

User

它有:

Name
Age

那接下來還要做:

JSON 欄位 name

對應 User.Name

JSON 欄位 age

對應 User.Age

最後才建立:

User
├── Name = Andy
└── Age = 20

這個從資料格式轉成程式物件的過程,通常稱為:

Deserialization

也就是「反序列化」。

Serialization 和 Deserialization 是什麼?

這兩個名詞很常一起出現。

Serialization 可以理解成:

程式物件

轉成某種可儲存或傳輸的格式

例如:

C# User Object

JSON

{"name":"Andy","age":20}

而 Deserialization 則反過來:

JSON

轉回程式物件

也就是:

{"name":"Andy","age":20}

User
├── Name = Andy
└── Age = 20

所以:

Serialization
→ Object 變成資料格式

Deserialization
→ 資料格式變成 Object

HTTP Body 和 JSON 是同一件事嗎?

不是。

這裡很容易混在一起。

Request Body 是 HTTP Message 裡的一部分。

JSON 則是一種資料格式。

所以:

Request Body

裡面可能放 JSON

但 Body 不一定是 JSON。

也可能是:

純文字
HTML
Form Data
Binary Data
其他格式

所以 Framework 要先看:

Content-Type

如果看到:

Content-Type: application/json

才知道:

這個 Body 應該按照 JSON 來理解。

整個流程就變成:

Request

Headers

Content-Type = application/json

Body

JSON

Deserialization

C# Object

Content-Type 再次變重要

前幾天學到:

Content-Type

用來描述 Body 的資料類型。

今天它開始直接決定:

Framework 要用什麼方式解析 Body。

例如:

Content-Type: application/json

Framework 會把 Body 當成 JSON。

如果是:

Content-Type: text/plain

那 Body 可能只當成一般文字。

所以 Framework 不會只看到 Body 就立刻反序列化。

它通常會先理解:

這份 Body 是什麼格式?

再決定:

應該用哪一種 Parser。

System.Text.Json 是做什麼的?

在 .NET 裡,一個常用的 JSON 處理工具就是:

System.Text.Json

它可以把 C# 物件轉成 JSON。

也可以把 JSON 反序列化成 C# 物件。

例如概念上:

JSON

JsonSerializer.Deserialize()

User Object

所以 Framework 並不是自己一個字一個字猜:

這是 Name。

這是 Age。

而是會使用專門的 JSON Parser / Serializer 來理解 JSON 格式。

Framework 只是幫我們把這些步驟串起來。

那 ASP.NET Core 為什麼可以直接給我 Model?

假設 Client 傳:

POST /users

Body:

{"name":"Andy","age":20}

ASP.NET Core 可能會做很多事情。

概念上可以先理解成:

收到 HTTP Request

解析 Headers

知道 Content-Type 是 application/json

讀取 Request Body

使用 JSON Serializer

建立指定的 C# Model

把 Model 交給 Handler / Controller

所以我們平常看到的:

User user

其實已經是 Framework 做完很多工作的結果。

Model Binding 又是什麼?

這裡開始會碰到一個常見名詞:

Model Binding

簡單理解,Framework 會嘗試把 Request 裡的資料,整理成 Handler 所需要的參數或 Model。

資料來源可能包括:

Route
Query
Headers
Form
Body

例如:

/users/10

可能把 10 綁定成:

id = 10

而:

?name=Andy

可能綁定成:

name = Andy

JSON Body:

{"name":"Andy","age":20}

則可能轉成:

User user

所以 Model Binding 可以理解成:

Request 裡的資料

Framework 整理

對應到程式參數 / Model

而 JSON Deserialization 則可能是這個過程中的其中一部分。

為什麼這件事情對 Mini Web Framework 很重要?

因為如果我們之後希望自己的 Framework 使用方式變得像:

Handler(User user)

那 Framework 就必須知道:

Request Body 在哪裡?

Content-Type 是什麼?

Body 是不是 JSON?

JSON 怎麼解析?

JSON 要轉成哪一個 C# Type?

所以真正做到這裡時,Framework 已經不只是:

接 Request

找 Route

回 Response

而是開始幫 Handler 準備資料。

也就是:

HTTP

Framework

C# 世界

這個轉換開始變得更完整。

今天的認知更新

以前的我:

JSON

C# Object

現在的我:

Client

HTTP Request

Headers

Content-Type

Body

JSON Text

JSON Parsing

Deserialization

C# Object

Handler 使用

也就是說:

JSON 並不會自己變成 C# Object。

Framework 必須先知道 Body 的資料格式,再使用相對應的 Parser 和 Serializer,最後才建立程式物件。

今日最大的發現

今天最大的發現是:

HTTP 和 JSON 其實是兩個不同層次。

HTTP 負責:

Request 怎麼傳
Headers 怎麼表示
Body 在哪裡

JSON 負責:

Body 裡面的資料要怎麼表示

最後 Framework 再負責:

把 HTTP 裡的 JSON

轉成 C# 可以使用的 Object

所以可以整理成三層:

TCP

傳 bytes

HTTP

定義 Request / Response 格式

JSON

定義資料格式

Framework

把這些底層資料轉成 C# Object

這讓前幾天學過的東西又串起來了。


在 .NET 中,可以使用 System.Text.Json 進行 JSON Serialization 與 Deserialization。

也就是可以把物件轉成 JSON,也可以把 JSON 轉成指定的 .NET Type。

ASP.NET Core 則會在 Request Processing 過程中處理 Request Body,並根據設定與 Content-Type 等資訊,將資料轉換成應用程式可以使用的形式。

所以平常在 Handler 或 Controller 裡直接取得 Model,其實是一層很高階的抽象。

背後仍然需要:

讀 Body

判斷 Content-Type

解析 JSON

建立 Object

🛠 與 Mini Web Framework 的關聯

目前 Mini Web Framework 的流程已經慢慢變成:

Browser

TCP

HTTP Request

HttpRequest
├── Method
├── Path
├── Headers
├── Query
└── Body

Routing

Handler

而今天又多出一層:

Body

Content-Type

JSON

Deserialization

C# Object

未來如果繼續做下去,就有機會讓 Handler 不再直接接觸:

raw JSON string

而是直接使用:

C# Model

這會讓 Framework 又更靠近平常使用 ASP.NET Core 的感覺。

今天暫時不實作

今天一樣先把概念想清楚。

因為 Day16~Day19 的 Request Parsing 實作之後還需要一起補完。

等那些基礎補上後,再實作 JSON Deserialization 會比較合理。

否則如果連 Request Body 都還沒有真正讀完整,就直接做 JSON Deserialize,會把中間很重要的 HTTP 問題跳過。

所以目前先記住整個方向:

Raw Body

Content-Type

JSON Parser

Deserialization

C# Object

之後再把它真正加入 Mini Web Framework。

結尾

今天原本只是想知道:

為什麼 JSON 可以變成 C# Object?

但一路拆下來後,我才發現這件事情其實跨越了好幾層。

Client 最開始只是把資料放進 HTTP Request Body。

Framework 必須先讀到完整 Body,再透過 Content-Type 知道它是 JSON。

接著才能讓 JSON Serializer 去解析文字,最後建立 C# Object。

所以以前看到:

User user

會覺得這只是一個很普通的 Handler Parameter。

但現在可以看到它背後其實經過:

TCP bytes

HTTP Request

Request Body

JSON

Deserialization

User Object

這也是 Framework 一直在替開發者做的事情:

把底層格式和傳輸細節,逐步轉換成我們熟悉的程式概念。


現在 Framework 已經開始可以想像把:

JSON

轉成 C# Object

但這時又有一個新的問題。

如果 Handler 想要的不是同一種資料呢?

例如:

/users 需要 User

/products 需要 Product

/login 需要 LoginRequest

Framework 怎麼知道每個 Handler 到底需要什麼參數?

難道每個 Route 都要自己寫一套解析邏輯嗎?

所以新的問題會是:

Framework 到底怎麼知道 Handler 需要哪些參數?


上一篇
POST 傳來的資料到底藏在哪裡?Request Body 又是什麼?
系列文
程式設計沒有告訴你的事:30 天破解每一個 Why20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言